/************************************************************************
 * AIDE - Automata Identification Engine
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     
 * Description  :     
 * Change log   :     	-Date:  Change
 ************************************************************************/

using System;
using SMLib.Automata.MM;
using SMLib.Automata.Base;

namespace AIDE.Filters.NFMs
{
	/// <summary>
	/// A confidence model (when you have a SUL and also its correct model).
	/// Agreegating the result of a SUL and a MM but preffere the MM if the
	/// result were not the same.
	/// </summary>
	public class Filter_MM_Confidence: IBlackBox_MM
	{
		IBlackBox_MM SUT;
		MealyMachine machine;
		MealyMachine.Mealy_State currentNode;
		const bool hasNondeterminism = false;
		bool somethingsWrong;

		/// <summary>
		/// Initializes a new instance of the <see cref="AIDE.Filters.NFMs.Filter_MM_Confidence"/> class.
		/// </summary>
		/// <param name='SUT'>
		/// The system  under learning
		/// </param>
		/// <param name='machine'>
		/// The known model of SUL
		/// </param>
		public Filter_MM_Confidence (IBlackBox_MM SUT, MealyMachine machine)
		{
			this.machine = machine;
			this.SUT = SUT;
			this.currentNode = machine [0];
			somethingsWrong = false;
		}

		#region IBlackBox_MealyMachine implementation
		public void Reset ()
		{
			SUT.Reset ();
			currentNode = machine [0];
			somethingsWrong = false;
		}

		public SMLib.Automata.Base.ISymbol Step (SMLib.Automata.Base.ISymbol input)
		{
			Console.Write("|");
			if (somethingsWrong) {
				if (currentNode == null)
					return null;
				//* return the corresponding output in the model
				foreach (MealyMachine.Mealy_Transition tr in currentNode.Transitions) {
					if (input.Equals (tr.inLabel)) {
						currentNode = tr.Destination;
						return tr.outLabel;
					}
				}
				currentNode = null;
				return null;
			} else {
				ISymbol o1 = SUT.Step (input);
				ISymbol o2 = null;
				//MealyMachine.Mealy_State tmpState=null;
				foreach (MealyMachine.Mealy_Transition tr in currentNode.Transitions) {
					//* for now, we assume it is deterministic!
					if (input.Equals (tr.inLabel)) {
						o2 = tr.outLabel;
						currentNode = tr.Destination;
						break;
					}
				}
				if (o2 == null)
				{
					//Console.Write("O2 is null");
					currentNode = null;
				}

				if (o1 != null && o2 != null && o1.Equals (o2)) {
					//* correct!
					return o1;
				} 
				else if(o1==null && o2==null)
				{
					return o1;
				}
				else{
					//* incorrect!
					Console.WriteLine ("\n**********SOMETHING IS WRONG in execution!*********");
					Console.WriteLine ("For input" + input + " the output " + o2 + " was expect but seen " + o1+"\n");
					somethingsWrong = true;
					return o1;
				}
			}
		}

		public SMLib.Automata.Base.Alphabet InputAlphabet {
			get {
				//* off course the machine input alphabet should be the same!
				return SUT.InputAlphabet;
			}
		}
		#endregion
	}
}

